import base64
import json
import pickle

from django.http import HttpResponseBadRequest
from django.http import JsonResponse
from django.shortcuts import render

# Create your views here.
from django.views import View




# 添加购物车后端逻辑实现
from django_redis import get_redis_connection

from apps.goods.models import SKU
from utils.response_code import RETCODE


class CartsView(View):
    def post(self,request):
        # 1.接收数据,判断商品信息
        import json
        data = json.loads(request.body.decode())
        sku_id = data.get("sku_id")
        count = data.get("count")
        if not all([sku_id,count]):
            return JsonResponse({"code":RETCODE.PARAMERR,"errmsg":"参数不全"})
        try:
            sku = SKU.objects.get(id=sku_id)
        except SKU.DoesNotExist:
            return JsonResponse({"code":RETCODE.NODATAERR,"errmsg":"没有次商品"})

        try:
            count=int(count)
        except Exception:
            return JsonResponse({"code":RETCODE.PARAMERR,"errmsg":"参数错误"})

        # 添加购物车默认就是选中
        selected = True
        # 2.先获取用户信息
        user = request.user
        # 3.根据用户是否登陆来判断
        # is_authenticated 是认证用户(注册用户)
        if user.is_authenticated:
            # 4.登录用户操作数据(redis):
            # 4.1连接数据库
            redis_conn = get_redis_connection("carts")
            # 4.2操作数据库
            redis_conn.hset("cart_%s"%user.id,sku_id,count)


            # 一.创建管道
            pl =redis_conn.pipeline()
            # 二.将指令收集到管道中 hincrby自动累加
            pl.hincrby("carts_%s"%user.id,sku_id,count)
            # set
            pl.sadd("selected_%s"%user.id,sku_id)
            # 三.执行管道
            pl.execute()



            # redis_conn.sadd("selected_%s"%user.id,sku_id)
            # 4.3返回响应
            return JsonResponse({"code":RETCODE.OK,"errmsg":"ok"})
        else:
            # 5.用户未登录操作cookie
            # 5.0先获取cookie中,可能存在的数据
            cart_str = request.COOKIES.get("carts")
            if cart_str is None:
                # 说明没有购物车数据
                cookie_data = {
                    sku_id:{"count":count,"selected":True}
                }
            else:
                # 说明有购物车数据
                # 先base64解码
                decode_data = base64.b64decode(cart_str)
                # 在bytes转字典
                cookie_data = pickle.loads(decode_data)
                # 再需要进行判断
                # 商品id是否在字典中
                if sku_id in cookie_data:
                    # 累加数量
                    origin_count = cookie_data[sku_id]["count"]
                    count+=origin_count+count
                    # 更新字典数据
                    cookie_data[sku_id]={"count":count,"selected":True}
                else:
                    cookie_data[sku_id]={"count":count,"selected":True}

            # 5.1组织数据的分析
            """
           {
               sku_id:{count:5,selected:True},
               sku_id:{count:2,selected:False},
               sku_id:{count:7,selected:True},
           }
           """
            # 5.2对数据进行编码
            # 字典转bytes
            cookie_bytes = pickle.dumps(cookie_data)
            # base64编码
            cookie_str = base64.b64encode(cookie_bytes)
            # 5.3设置cooike
            response = JsonResponse({"code":RETCODE.OK,"errmsg":"ok"})

            response.set_cookie("carts",cookie_str,max_age=7*24*3600)

            # 5.4返回响应
            return response







######################以下代码为编码################################

# import pickle
# import base64
# # 组织数据
# carts={
#     '1':{'count':5,'selected':True}
# }
# # 5.1 将字典转换为二进制
# bytes_data=pickle.dumps(carts)
#
# # 5.2 再进行base64编码
# encode_data=base64.b64encode(bytes_data)
# encode_data
#
# #####################以下代码为解码#####################################
# # 5.3 先将base64解码
# decode_data=base64.b64decode(encode_data)
# # 5.4 将bytes类型转换为字典
# pickle.loads(decode_data)



    # 购物车展示
    def get(self,request):
        # 1.先获取用户信息
        user=request.user
        if user.is_authenticated:
            # 3.如果用户登录,则从redis中获取信息
            # 3.1.链接redis
            redis_conn = get_redis_connection("carts")
            # 3.2获取redis数据
            id_counts = redis_conn.hgetall("carts_%s"%user.id)
            selected_ids=redis_conn.smembers("selected_%s"%user.id)
            # 将redis数据转换为cookie格式
            cookie_dict = {}
            for sku_id,count in id_counts.items():
                # if sku_id in selected_ids:
                #     selected = True
                # else:
                #     selected = False
                cookie_dict[int(sku_id)]={
                    "count":int(count),
                    "selected":sku_id in selected_ids
                }
        else:
            # 2.如果用户为登录,则从cookie中获取信息
            cookie_data = request.COOKIES.get("carts")
            if cookie_data is not None:
                # 先进行解码
                cookie_dict=pickle.loads(base64.b64decode(cookie_data))
            else:
                cookie_dict={}
        # 4.获取商品id 因为redis的数据结构和cookie的数据结构不一致
        # 我们应该让他们的数据一致
        ids = cookie_dict.keys()

        # 5.根据商品id进行商品信息的查询
        carts_list=[]
        for id in ids:
            sku = SKU.objects.get(id=id)
            # 6.将对象转换为字典
            carts_list.append({
                'id': sku.id,
                'name': sku.name,
                'count': cookie_dict.get(sku.id).get('count'),
                'selected': str(cookie_dict.get(sku.id).get('selected')),  # 将True，转'True'，方便json解析
                'default_image_url': sku.default_image.url,
                'price': str(sku.price),  # 从Decimal('10.2')中取出'10.2'，方便json解析
                'amount': str(sku.price * cookie_dict.get(sku.id).get('count')),
            })
        # 7.返回响应
        return render(request,"cart.html",context={'cart_skus':carts_list})



##################修改购物车#####################################
    def put(self,request):
        # 1.接收数据
        data = json.loads(request.body.decode())
        sku_id=data.get("sku_id")
        count = data.get("count")
        selected=data.get("selected")
        # 2.验证数据
        # 判断参数是否齐全
        if not all([sku_id,count]):
            return HttpResponseBadRequest("缺少参数")
        # 判断商品id是否存在
        try:
            sku = SKU.objects.get(id=sku_id)
        except SKU.DoesNotExist:
            return HttpResponseBadRequest("商品不存在")
        # 判断count是否为数字
        try:
            count = int(count)
        except Exception:
            return HttpResponseBadRequest("参数count有误")
        # 判断selected是否为bool值
        if selected:
            if not isinstance(selected,bool):
                return HttpResponseBadRequest("参数count有误")
        # 判断是否为登录用户
        # 3.获取用户信息
        user = request.user
        if user.is_authenticated:
            # 4.登录用户更新redis
            # 4.1链接redis
            redis_conn = get_redis_connection("carts")
            # 4.2更新数据
            # hash
            redis_conn.hset("carts_%s"%user.id,sku_id,count)
            # set
            if selected:
                redis_conn.sadd("selected_%s"%user.id,sku_id)
            else:
                redis_conn.srem("selected_%s"%user.id,sku_id)
            # 4.3返回响应
            data={
                'count': count,
                'id': sku_id,
                'selected': selected,
                'name': sku.name,
                'default_image_url': sku.default_image.url,
                'price': sku.price,
                'amount': sku.price * count,
            }
            return JsonResponse({"code":RETCODE.OK,"errmsg":"ok","cart_sku":data})
        else:
            # 5.未登录用户更新cookie
            # 5.1获取cookie中的数据,并进行判断
            cookie_str = request.COOKIES.get("carts")
            if cookie_str is None:
                # 如果有数据需要进行解码
                cookie_dict = pickle.loads(base64.b64decode(cookie_str))
            else:
                cookie_dict={}
            # 5.2更新数据
            # sku_id 是否存在字典列表中
            if sku_id in cookie_dict:
                cookie_dict[sku_id]={
                    "count":count,
                    "selected":selected
                }
            # 5.3将字典进行编码
            cookie_data = base64.b64encode(pickle.dumps(cookie_dict))
            # 5.4设置cookie
            data={
                'count': count,
                'id': sku_id,
                'selected': selected,
                'name': sku.name,
                'default_image_url': sku.default_image.url,
                'price': sku.price,
                'amount': sku.price * count,
            }
            response = JsonResponse({"code":RETCODE.OK,"errmsg":"ok","cart_sku":data})
            response.set_cookie("carts",cookie_data,max_age=7*24*3600)

            # 5.5返回响应
            return response




###################删除购物车###########################
    def delete(self,request):
        # 1.接收数据
        data = json.loads(request.body.decode())
        sku_id=data.get("sku_id")
        # 2.验证数据
        try:
            # pk primary kuy 主键
            sku = SKU.objects.get(pk = sku_id)
        except SKU.DoesNotExist:
            return JsonResponse({"code":RETCODE.NODATAERR,"errmsg":"没有此数据"})

        # 3获取用户信息,并进行判断
        user = request.user

        if user.is_authenticated:
            # 4.登录则操作redis
            # 4.1链接redis
            redis_conn = get_redis_connection("carts")
            # 4.2hash
            redis_conn.hdel("carts_%s"%user.id,sku_id)
            #set
            redis_conn.srem("selected_%s"%user.id,sku_id)
            # 4.3返回响应
            return JsonResponse({"code":RETCODE.OK,"errmsg":"ok"})

        else:
            # 未登录则操作cookie
            #5.1先获取cookie数据,并进行判断
            cookie_str = request.COOKIES.get("carts")
            if cookie_str is None:
                # 如果有数据,则进行解码
                cookie_dict = pickle.loads(base64.b64decode(cookie_str))
            else:
                cookie_dict={}
            #5.2删除数据
            if sku_id in cookie_dict:
                del cookie_dict[sku_id]
                # 5.3对数据进行编码
                cookie_data=base64.b64encode(pickle.dumps(cookie_dict))
                # 5.4设置cookie
                response = JsonResponse({"code":RETCODE.OK,"errmsg":"ok"})
                response.set_cookie("carts",cookie_data,max_age=7*24*3600)
                # 5.5返回响应
                return response








